Class {
	#name : 'RGStampParser',
	#superclass : 'Object',
	#category : 'Ring-Core-Parsing',
	#package : 'Ring-Core',
	#tag : 'Parsing'
}

{ #category : 'parsing' }
RGStampParser class >> authorForStamp: aString [

	^ aString isEmptyOrNil
		ifTrue: [ self historicalStamp ]
		ifFalse: [ self parseAuthorAliasFrom: aString ]
]

{ #category : 'parsing' }
RGStampParser class >> historicalStamp [

	^ '<historical>'
]

{ #category : 'parsing' }
RGStampParser class >> parseAuthorAliasFrom: aString [

	^ self new basicParseAuthorAliasFrom: aString
]

{ #category : 'parsing' }
RGStampParser class >> parseTimestampFrom: aString [

	^ self new parseTimestampFrom: aString
]

{ #category : 'parsing' }
RGStampParser class >> timeForStamp: stamp [

	^ self new timeForStamp: stamp
]

{ #category : 'parsing stamp' }
RGStampParser >> basicParseAuthorAliasFrom: aString [
	"Parse an alias/name of the author from a string that is extracted from a source file. If there is no alias/name we return emtpy string."

	| tokens dateStartIndex unknown |
	"The following timestamp strings are supported:
		<authorname><date><time>.
		<authorname><date>
		<date><time>
		<date><time><authorname>
		<date><authorname>
		<historical>
	All fields can be separated by spaces or line ends but a separator between author alias/name and date can be missing as well"
	"unknown:= 'unknown'."

	aString = '<historical>' ifTrue: [ ^ aString ].

	unknown := nil.
	aString isEmptyOrNil
		ifTrue: [ ^ unknown ].
	dateStartIndex := (aString indexOf: $-) - 1.	"If there is no / character in the timestamp, no author alias/name exists"
	dateStartIndex = -1
		ifTrue: [ ^ unknown ].
	^ [
	"Go the start of the date string (there can be 1 or 2 digits and a space separator can be missing at the front!!)"
	[dateStartIndex >= 4 and: [ (aString at: dateStartIndex - 1) isDigit ]]
		whileTrue: [ dateStartIndex := dateStartIndex - 1 ].	"Extract only those tokens that do not possible represent date or time - meaning that authorname may be at the end"
	tokens := (aString copyFrom: dateStartIndex to: aString size) substrings
		reject: [ :token | (token occurrencesOf: $-) = 2 or: [ (token occurrencesOf: $:) = 1 ] ].	"only one token should be left if author name/alias exists"
	^ tokens isEmpty
		ifTrue: [
			"if dateStartIndex is not 1 then the authorname may be at the beginning"
			dateStartIndex > 1
				ifTrue: [ (aString copyFrom: 1 to: dateStartIndex - 1) trimBoth ]
				ifFalse: [ unknown ] ]
		ifFalse: [ tokens first ] ]
		on: Exception
		do: [ :e | unknown ]
]

{ #category : 'parsing stamp' }
RGStampParser >> parseAuthorAliasFrom: aString [
	"Allows other applications  to treat a different empty alias by overriding this method"

	^self basicParseAuthorAliasFrom: aString
]

{ #category : 'parsing' }
RGStampParser >> parseTimestampFrom: aString [

	^self parseTimestampFrom: aString default: nil
]

{ #category : 'parsing' }
RGStampParser >> parseTimestampFrom: aString default: anObject [
	"Parse and answer a date-time from a timestamp string that is extracted from a source file.
	 Answer the default value if there is no timestamp, or it is not formatted as expected."

	^ (DateAndTime fromMethodTimestamp: aString) ifNil: [ anObject ]
]

{ #category : 'parsing stamp' }
RGStampParser >> timeForStamp: stamp [

	^ stamp
		ifNil: [ 	DateAndTime new]
		ifNotNil: [
			| substrings |
			substrings := stamp substrings.
			([(DateAndTime fromString: (' ' join: substrings allButFirst ))] on: Exception do: [DateAndTime epoch]) ]
]
